﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace DiscreteMath.Tests
{
    public class ContextFreeGrammarFactory : TestFactory<ContextFreeGrammar>
    {
        private static ContextFreeGrammarFactory instance = new ContextFreeGrammarFactory();

        private TestableContextFreeGrammar
            matchedAsAndBs,
            algrebraicExpressions;

        private ContextFreeGrammarFactory()
        {

        }

        public static ContextFreeGrammarFactory Factory
        {
            get { return instance; }
        }

        public TestableContextFreeGrammar MatchedAsAndBs
        {
            get
            {
                if (matchedAsAndBs == null)
                {
                    var nonterminals = new HashSet<char>() { 'S' };
                    var terminals = new HashSet<string>() { "a", "b" };
                    var rules = new RuleDictionary()
                    {
                        { 'S', new List<String>() { SpecialSigns.EmptyWord.ToString(), "aSb" } },
                    };
                    var starting = 'S';

                    var grammar = new ContextFreeGrammar(nonterminals, terminals, rules, starting);
                    string name = "L = { w | w = a^nb^n }";
                    Func<string, bool> test = (word) =>
                    {
                        if (word.Length % 2 != 0)
                            return false;

                        int numberOfAs = word.Count(x => x == 'a');
                        int numberOfBs = word.Count(x => x == 'b');

                        return numberOfAs == numberOfBs && word.Substring(0, numberOfAs).All(x => x == 'a');
                    };

                    matchedAsAndBs = new TestableContextFreeGrammar(grammar, name, test);
                }

                return matchedAsAndBs;
            }
        }

        public TestableContextFreeGrammar AlgebraicExpressions
        {
            get
            {
                if (this.algrebraicExpressions == null)
                {
                    var nonterminals = new HashSet<char>() { 'S' };
                    var terminals = new HashSet<string>() { "id", "+", "-", "*", "/", "(", ")", " " };
                    var rules = new RuleDictionary()
                    {
                        { 'S', new List<string>() { "id", "(S)", "S + S", "S - S", "S * S", "S / S" } },
                    };

                    this.algrebraicExpressions = new TestableContextFreeGrammar(
                        new ContextFreeGrammar(nonterminals, terminals, rules, 'S'), 
                        "Algebraic expressions",
                        (word) => true);
                }

                return this.algrebraicExpressions;
            }
        }
    }
}
